#pragma once

#include <iostream>
#include <vector>
#include <queue>
#include <pthread.h>
#include <cstdlib>
#include <unistd.h>
#include <functional>
#include "Task.hpp"

class ThreadInfo
{
public:
    pthread_t tid_;
    std::string name_;
};

template <class T>
class ThreadPool
{
    static const int defaultnums = 5; // 线程池线程数量
private:
    std::vector<ThreadInfo> threads_; // 组织线程
    std::queue<T> taskQueue_;         // 任务队列

    // 维护任务队列的线程安全与线程的同步
    pthread_mutex_t mutex_;
    pthread_cond_t cond_;

    // 实现单例
    static ThreadPool<T> *tp;
    static pthread_mutex_t lock_;

public:
    ThreadPool(int threadNums = defaultnums) : threads_(threadNums)
    {
        pthread_mutex_init(&mutex_, nullptr);
        pthread_cond_init(&cond_, nullptr);
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&cond_);
    }

private:
    static void *Handle(void *args)
    {
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(args);
        while (true)
        {
            pthread_mutex_lock(&tp->mutex_);

            // 临界资源不满足，去条件变量中等待。while防止伪唤醒
            while (tp->taskQueue_.empty())
            {
                pthread_cond_wait(&tp->cond_, &tp->mutex_);
            }
            // 获取一个任务
            T task = tp->Pop();
            //执行任务
            task();
            pthread_mutex_unlock(&tp->mutex_);
        }
    }

    std::string GetName(pthread_t tid)
    {

        
        for (int i = 0; i < threads_.size(); i++)
        {
            if (tid == threads_[i].tid_)
            {
                return threads_[i].name_;
            }
        }
        return "None";
    }

    T Pop()
    {
        // 这里不需要加锁，应该这个函数是在持有锁的情况调用的，在加锁会发生死锁
        T tmp = taskQueue_.front();
        taskQueue_.pop();
        return tmp;
    }

public:
    void Push(const T &out)
    {
        pthread_mutex_lock(&mutex_);
        taskQueue_.push(out);

        // 唤醒一个线程
        pthread_cond_signal(&cond_);

        pthread_mutex_unlock(&mutex_);
    }

    static ThreadPool<T> *GetInstance()
    {
        if (tp == nullptr)
        {
            pthread_mutex_lock(&lock_);
            if (tp == nullptr)
            {
                tp = new ThreadPool<T>;
            }
            pthread_mutex_unlock(&lock_);
        }

        return tp;
    }

public:
    void start()
    {
        // 创建线程
        for (int i = 0; i < threads_.size(); i++)
        {
            pthread_create(&(threads_[i].tid_), nullptr, Handle, this);
            threads_[i].name_ = "Thread-" + std::to_string(i + 1);
            usleep(10);
        }
    }
};

template <class T>
ThreadPool<T> *ThreadPool<T>::tp = nullptr;
template <class T>
pthread_mutex_t ThreadPool<T>::lock_ = PTHREAD_MUTEX_INITIALIZER;